#include "instructions/stack/dup.h"

namespace jvm {
namespace instructions {

void DUP::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    auto slot = stack->popSlot();
    stack->pushSlot(slot);
    stack->pushSlot(slot);
}

void DUP_X1::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    auto slot1 = stack->popSlot();
    auto slot2 = stack->popSlot();
    stack->pushSlot(slot1);
    stack->pushSlot(slot2);
    stack->pushSlot(slot1);
}

void DUP_X2::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    auto slot1 = stack->popSlot();
    auto slot2 = stack->popSlot();
    auto slot3 = stack->popSlot();
    stack->pushSlot(slot1);
    stack->pushSlot(slot3);
    stack->pushSlot(slot2);
    stack->pushSlot(slot1);
}

void DUP2::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    auto slot1 = stack->popSlot();
    auto slot2 = stack->popSlot();
    stack->pushSlot(slot2);
    stack->pushSlot(slot1);
    stack->pushSlot(slot2);
    stack->pushSlot(slot1);
}

void DUP2_X1::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    auto slot1 = stack->popSlot();
    auto slot2 = stack->popSlot();
    auto slot3 = stack->popSlot();
    stack->pushSlot(slot2);
    stack->pushSlot(slot1);
    stack->pushSlot(slot3);
    stack->pushSlot(slot2);
    stack->pushSlot(slot1);
}

void DUP2_X2::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    auto slot1 = stack->popSlot();
    auto slot2 = stack->popSlot();
    auto slot3 = stack->popSlot();
    auto slot4 = stack->popSlot();
    stack->pushSlot(slot2);
    stack->pushSlot(slot1);
    stack->pushSlot(slot4);
    stack->pushSlot(slot3);
    stack->pushSlot(slot2);
    stack->pushSlot(slot1);
}

} // namespace instructions
} // namespace jvm